package org.ytor.core.sqlflow.builder.support;

import org.ytor.common.util.Strs;
import org.ytor.core.sqlflow.PersistenceModel;
import org.ytor.core.sqlflow.SFunction;
import org.ytor.core.sqlflow.builder.AbsBuilder;
import org.ytor.core.sqlflow.builder.IOrderedParams;
import org.ytor.core.sqlflow.executor.DMLResult;
import org.ytor.core.sqlflow.executor.SQLRuntime;
import org.ytor.core.sqlflow.log.SqlLogHelper;
import org.ytor.core.sqlflow.plugin.Interceptor;
import org.ytor.core.sqlflow.plugin.InterceptorManager;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * UPDATE 构建器（SQL 原生风格）
 * 目标用法：
 *   new UpdateBuilder<>()
 *       .update(SysUser.class)
 *       .set(SysUser::getName, "Alice")
 *       .set("age", 18)
 *       .where(w -> w.eq("id", "123"))
 *       .start();
 *
 * 说明：
 * - 不再从实体反射抽取非空字段；仅按 set(...) 指定的列生成 SET 子句。
 * - 参数顺序：先 SET 的参数，后 WHERE 的参数。
 * - where(...) 使用你已有的 WhereBuilder。
 */
public class UpdateBuilder<T extends PersistenceModel<T, ?>> extends AbsBuilder implements IOrderedParams {

    /**
     * 表实体类
     */
    private Class<?> table;

    /**
     * 表名称
     */
    private String tableName;

    /**
     * SET 列和值（保持插入顺序）
     */
    private final LinkedHashMap<String, Object> setMap = new LinkedHashMap<>();
    /**
     * WHERE 子句
     */
    private WhereBuilder where;

    // ------------------------------------------------------------ API

    /**
     * 绑定更新的表（返回一个新 builder，令调用链可从 diamond 推断具体泛型）。
     * 用法： new UpdateBuilder<>().update(SysUser.class).set(...)
     */
    public <E extends PersistenceModel<E, ?>> UpdateBuilder<E> update(Class<E> table) {
        UpdateBuilder<E> b = new UpdateBuilder<>();
        b.table = table;
        b.tableName = getTableName(table);
        return b;
    }

    /** 设置列（字符串列名） */
    public UpdateBuilder<T> set(String column, Object value) {
        if (Strs.isEmpty(column)) return this;
        setMap.put(column.trim(), value);
        return this;
    }

    /** 设置列（方法引用列名） */
    public UpdateBuilder<T> set(SFunction<T, ?> column, Object value) {
        setMap.put(resolveField(column), value);
        return this;
    }

    /** WHERE 构造 */
    public UpdateBuilder<T> where(Consumer<WhereBuilder> consumer) {
        WhereBuilder w = new WhereBuilder(null); // 保持与你现有 WhereBuilder 构造一致
        consumer.accept(w);
        this.where = w;
        return this;
    }

    // ------------------------------------------------------------ Build & Params

    @Override
    public String toSql() {
        if (table == null && Strs.isEmpty(tableName)) {
            SqlLogHelper.error("UPDATE 缺少表, 请检查");
            throw new IllegalStateException("UPDATE 缺少表, 请检查");
        }
        if (setMap.isEmpty()) {
            throw new IllegalStateException("UPDATE 操作的set集合为空");
        }
        String setClause = setMap.keySet().stream()
                .map(col -> col + " = ?")
                .collect(Collectors.joining(", "));

        String whereSql = (where == null) ? "" : where.toSql();

        return "UPDATE\n\t" + tableName + "\nSET\n\t" + setClause + whereSql;
    }

    private String toInnerSql() {
        List<Interceptor> interceptors = InterceptorManager.interceptors();
        for (Interceptor interceptor : interceptors) {
            interceptor.beforeUpdateBuilder(table, tableName, where);
        }
        return toSql();
    }

    @Override
    public List<Object> orderedParams() {
        List<Object> params = new ArrayList<>(setMap.values());
        if (where != null) params.addAll(where.orderedParams());
        return params;
    }

    /**
     * 提交SQL执行
     */
    public DMLResult submit() {
        String whereSql = (where == null) ? "" : where.toSql();
        if (Strs.isEmpty(whereSql)) {
            SqlLogHelper.error("UPDATE 缺少 WHERE 条件, 已拦截该全表更新操作");
            throw new IllegalStateException("UPDATE 缺少 WHERE 条件, 已拦截该全表更新操作");
        }
        String sql = toInnerSql();

        // UPDATE执行前
        List<Interceptor> interceptors = InterceptorManager.interceptors();
        for (Interceptor interceptor : interceptors) {
            interceptor.beforeUpdate(table, tableName, sql, where, orderedParams());
        }

        DMLResult result = SQLRuntime.doUpdate(sql, orderedParams());

        // UPDATE执行后
        for (Interceptor interceptor : interceptors) {
            interceptor.afterUpdate(table, tableName, sql, where, orderedParams(), result);
        }
        return result;
    }

}
